package dev.ece.suit.hexmap;

import java.io.InputStream;
import java.util.Map;

import org.lwjgl.opengl.GL20;

import dev.ece.core.light.Material;
import dev.ece.core.light.MaterialLocationHandler;
import dev.ece.core.shader.Shader;
import dev.ece.core.texture.FBOS;
import dev.ece.core.texture.Texture;
import dev.ece.suit.utils.ShaderFunctions;
import dev.ece.util.tools.Camera;

public class HexMapWaterShader extends Shader {

	public HexMapWaterShader(InputStream vertexShaderInputStream,
			InputStream pixelShaderInputStream, Map<String, String> functions) {
		super(vertexShaderInputStream, pixelShaderInputStream, functions);
	}

	@Override
	protected String getVertexHeader() {
		StringBuffer s = new StringBuffer();
		s.append(Material.getMaterialStructString());
		s.append(super.getVertexHeader());
		return s.toString();
	}

	@Override
	protected String getPixelHeader() {
		return this.getVertexHeader();
	}

	@Override
	protected String getVersion() {
		return "#version 330 core\n#extension GL_NV_shadow_samplers_cube : enable";
	}
	
	private MaterialLocationHandler materialLocationHanlder;
	
	private int noiseHandler;
	
	private int skyBoxHandler;
	
	private int distanceHandler;
	
	private int cameraHandler;
	
	private int backTextureHandler;
	
	@Override
	protected void onBindAttribLocations(int program) {
		GL20.glBindAttribLocation(program, 0, "ece_Vertex");
		GL20.glBindAttribLocation(program, 1, "ece_TexCoord");
	}

	@Override
	protected void onInitializeHandler(int program) {
		materialLocationHanlder = MaterialLocationHandler.newInstance(program, "material.");
		noiseHandler = GL20.glGetUniformLocation(program, "noise");
		skyBoxHandler = GL20.glGetUniformLocation(program, "skybox");
		distanceHandler = GL20.glGetUniformLocation(program, "distance");
		cameraHandler = GL20.glGetUniformLocation(program, "cameraPosition");
		backTextureHandler = GL20.glGetUniformLocation(program, "backTexture");
	}

	public void glDistance(float distance) {
		GL20.glUniform1f(distanceHandler, distance);
	}
	
	public void glCamera(Camera camera) {
		GL20.glUniform3f(cameraHandler, camera.position.getX(), 
				camera.position.getY(), camera.position.getZ());
	}
	
	public void glDefer(FBOS defer) {
		GL20.glUniform1i(backTextureHandler, defer.getTextures()[2].bind(2));
	}
	
	public void glNoise(Texture noise) {
		GL20.glUniform1i(noiseHandler, noise.bind(0));
	}
	
	public void glSkyBox(Texture skybox) {
		GL20.glUniform1i(skyBoxHandler, skybox.bind(1));
	}
	
	public void glMaterial(Material material) {
		material.glUniformMaterial(materialLocationHanlder);
	}
	
	@Override
	public void clearup() {
		GL20.glDeleteShader(noiseHandler);
		GL20.glDeleteShader(skyBoxHandler);
		GL20.glDeleteShader(cameraHandler);
		GL20.glDeleteShader(distanceHandler);
		GL20.glDeleteShader(backTextureHandler);
		materialLocationHanlder.clearup();
		super.clearup();
	}
	
	private static HexMapWaterShader hexMapWaterShader;
	
	public static HexMapWaterShader createHexMapWaterShader() {
		if(hexMapWaterShader == null) {
			hexMapWaterShader = new HexMapWaterShader(
					HexMapWaterShader.class.getClassLoader().getResourceAsStream("shaders/defer/watermapping.vert"),
					HexMapWaterShader.class.getClassLoader().getResourceAsStream("shaders/defer/watermapping.frag"), 
					ShaderFunctions.getFunctions());
		}
		return hexMapWaterShader;
	}

}
